feat(rpc): implement debug_traceCall endpoint - #2547
Conversation
Adds debug_traceCall, a traced dry-run of eth_call: it runs a call against a chosen point-in-time state and returns a Geth-style trace without the call ever being signed or mined. - evm_input: InspectorInput becomes an enum (Transaction | Call) - evm: split inspect into inspect_transaction / inspect_call with a shared run_tracer; inspect_call builds EvmInput from pending/mined block, no hash lookup, no block replay, empty CacheDB - executor: add trace_call mirroring trace_transaction, reusing the inspector worker pool - rpc_server: register debug_traceCall (CallInput, BlockFilter, options) - e2e: cover callTracer against latest and pending state Closes cloudwalk#2539
There was a problem hiding this comment.
Looks good to me.
✅ debug_traceCall is wired end-to-end (RPC registration → param parsing → point-in-time resolution → executor path → EVM inspector dispatch) with clean separation from debug_traceTransaction.
✅ The InspectorInput enum refactor is sensible and keeps transaction behavior isolated while enabling call tracing without tx lookup/replay.
✅ inspect_call correctly builds EvmInput from pending/mined state and resets the base session to the selected boundary before tracing, which aligns with dry-run semantics.
✅ Coverage added in e2e targets the important endpoint-specific risks:
- tracing a never-sent call
- pending-state trace does not persist mutations
I did not find concrete correctness/security/deploy-blocking issues in the provided diff.
|
Hi @carneiro-cw i already got a positive review on the agent, if you have some time to see would be good. If there is something that needs to change, just say it. Thanks!! |
Resolves the modify/delete conflicts introduced by the executor reorganization (cloudwalk#2597), which deleted evm.rs, evm_input.rs and executor.rs by splitting each into several files. The debug_traceCall changes were ported onto the new layout: - InspectorInput enum moved to evm/types/input/inspector.rs - inspect/inspect_transaction/inspect_call moved to evm/mod.rs; the shared run_tracer is now a free function generic over EvmInput, so it serves both TransactionExecutionInput and CallExecutionInput - inspect_call builds a CallExecutionInput via from_pending_block / try_from_mined_block instead of the removed EvmInput constructors, and resets the session with the input's own ExecutionKind - trace_call moved to Executor in executor/mod.rs - rpc_server.rs changes carried over to the renamed rpc/server.rs Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Summary
LGTM — this PR cleanly wires debug_traceCall end-to-end (RPC registration/param parsing → point-in-time resolution → executor dispatch → EVM tracer execution) while preserving debug_traceTransaction behavior via the shared run_tracer path.
I did not find concrete correctness/security/blocking issues in the provided diff. The InspectorInput enum split is coherent, inspect_call correctly avoids tx replay semantics, and the added e2e tests cover the two highest-risk behaviors for this endpoint (never-sent call tracing and non-persistence against pending state).
What
Implements
debug_traceCall(issue #2539) — a traced version ofeth_call.It runs an arbitrary call against a chosen point-in-time state and returns a
Geth-style trace, without the call having to be signed or mined first
(i.e. a dry-run simulation of
debug_traceTransaction).Signature:
debug_traceCall(call, block, options)wherecall—CallInput(from/to/value/data),block—BlockFilter(latest/pending/earliest/hash/number),options—GethDebugTracingOptions(tracer selection).How
evm_input.rs—InspectorInputbecomes an enum withTransactionandCallvariants (previously a transaction-only struct).evm.rs—inspectdispatches on the variant. Transaction logic isunchanged (renamed to
inspect_transaction); the tracer match block isextracted into a shared
run_tracer. Newinspect_callbuilds anEvmInputfrom the pending/mined block with no tx-hash lookup and no block replay.
executor.rs— newtrace_callmirrorstrace_transactionand reusesthe existing
inspectorworker pool (InspectorTask), so span propagationacross the worker-thread boundary is inherited unchanged.
rpc_server.rs— registersdebug_traceCall, parses the three params,resolves the block to a point-in-time, traces, and decorates the result.
Testing
just test— full Rust suite green (incl. the pre-existingdebug_traceTransactioncoverage, which sharesrun_tracer).just lint-check— clean.e2e-json-rpc.test.ts:callTracertraces a contract call that was never sent (latest),Compatibility
debug_traceTransactionis unchanged behaviorally — it takes the samerun_tracerpath; only the input plumbing was refactored.Closes #2539